﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace oSoft.ColorPicker
{
    [ToolboxBitmap(typeof(oSoftColorPicker), "oSoftColorPicker.bmp")]
    public partial class oSoftColorPicker : UserControl
    {
        protected Graphics _G;
        protected Image _ColorImage;
        protected oSoftColor c;
        protected string oldHexValue;

        public oSoftColorPicker()
        {
            InitializeComponent();
        }

        private void ColorPicker_Load(object sender, EventArgs e)
        {
            c = new oSoftColor();
            initializeColorImage();
            drawColorMap();
        }

        protected void initializeColorImage()
        {
            _ColorImage = new Bitmap(pbColor.Width, pbColor.Height);
            pbColor.Image = _ColorImage;
            _G = Graphics.FromImage(_ColorImage);
            _G.Clear(Color.Red);
        }


        /// <summary>
        /// Gets the Red component of the color in the range from 0 to 255
        /// </summary>
        [Description("Gets the Red component of the color in the range from 0 to 255")]
        public int R
        {
            get { return c.R; }
        }

        /// <summary>
        /// Gets the Green component of the color in the range from 0 to 255
        /// </summary>
        [Description("Gets the Green component of the color in the range from 0 to 255")]
        public int G
        {
            get { return c.B; }
        }

        /// <summary>
        /// Gets the Blue component of the color in the range from 0 to 255
        /// </summary>
        [Description("Gets the Blue component of the color in the range from 0 to 255")]
        public int B
        {
            get { return c.B; }
        }

        /// <summary>
        /// Gets the Hue of the color in the range from 0.0 to 1.0
        /// </summary>
        [Description("Gets the Hue of the color in the range from 0.0 to 1.0")]
        public double Hue
        {
            get { return c.Hue; }
        }

        /// <summary>
        /// Gets the Saturation of the color in the range from 0.0 to 1.0
        /// </summary>
        [Description("Gets the Saturation of the color in the range from 0.0 to 1.0")]
        public double Sat
        {
            get { return c.Sat; }
        }

        /// <summary>
        /// Gets the Luminosity of the color in the range from 0.0 to 1.0
        /// </summary>
        [Description("Gets the Luminosity of the color in the range from 0.0 to 1.0")]
        public double Lum
        {
            get { return c.Lum; }
        }

        /// <summary>
        /// Gets or Sets the the color through a System.Drawing.Color object
        /// </summary>        
        [Description("Gets or Sets the the color through a System.Drawing.Color object")]
        public Color Color
        {
            get
            {
                if (c == null)
                    return Color.FromArgb(0, 0, 0);
                else
                    return c.Color;
            }
            set
            {
                if (c == null)
                    c = new oSoftColor();

                oldHexValue = tbHex.Text;
                c.Color = value;
                paintColorImage();
                showValues();
               
            }
        }

        protected void showValues()
        {
            tbRed.Text = c.R.ToString();
            tbGreen.Text = c.G.ToString();
            tbBlue.Text = c.B.ToString();

            tbHue.Text = c.H.ToString();
            tbLuminosity.Text = c.L.ToString();
            tbSaturation.Text = c.S.ToString();

            tbHex.Text = string.Format("#{0:X2}{1:X2}{2:X2}", c.R, c.G, c.B);
            oldHexValue = tbHex.Text;
        }

        protected void paintColorImage()
        {
            if (pbColor.Image == null)
            {
                initializeColorImage();
            }
            _G.Clear(c.Color);
            pbColor.Refresh();
        }

        protected void drawColorMap()
        {
            int lum, sat, xstep, ystep, x0, y0, i;
            int n = 6;
            int hueStep = 20;

            lum = trkLuminosity.Value;
            sat = trkSaturation.Value;
            float startAngle = 0.0f;
            float currentAngle = 0.0f;
            ColorMap.Image = new Bitmap(ColorMap.ClientRectangle.Width, ColorMap.ClientRectangle.Height);

            Graphics g = Graphics.FromImage(ColorMap.Image);
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            ystep = ColorMap.Height / (2 * n);
            xstep = ColorMap.Width / (2 * n);

            x0 = ColorMap.Image.Width / 2;
            y0 = ColorMap.Image.Height / 2;

            for (i = n; i >= 1; i--)
            {
                lum = i * trkLuminosity.Value / n;
                Rectangle r = new Rectangle(x0 - i * xstep, y0 - i * ystep, 2 * i * xstep, 2 * i * ystep);
                for (int hue = 0; hue <= 360; hue += hueStep)
                {
                    oSoftColor c = oSoftColor.FromHSL((double)hue / 360, (double)sat / 255, (double)lum / 255);
                    Brush b = new SolidBrush(c.Color);
                    currentAngle = hue;
                    g.FillPie(b, r, startAngle, hueStep);
                    startAngle = currentAngle;
                }
            }
        }

        private void ColorPicker_Paint(object sender, PaintEventArgs e)
        {
            drawColorMap();
        }

        private void ColorMap_Click(object sender, EventArgs e)
        {
            Color = ((Bitmap)ColorMap.Image).GetPixel(lastMouseUpPosition.X, lastMouseUpPosition.Y);

            if (ColorSelected != null)
            {
                object s = this;
                oSoftColorPickerEventArgs ce = new oSoftColorPickerEventArgs();
                ce.color = Color;
                ColorSelected(s, ce);
            }          
        }

        private void trkSaturation_Scroll(object sender, EventArgs e)
        {
            drawColorMap();
        }

        private void trkLuminosity_Scroll(object sender, EventArgs e)
        {
            drawColorMap();
        }

        private Point lastMouseUpPosition;

        private void ColorMap_MouseDown(object sender, MouseEventArgs e)
        {
            lastMouseUpPosition = e.Location;
        }

        /// <summary>
        /// Event raised when a color is selected in the ColorPicker
        /// </summary>
        /// <param name="sender">The control where de event was fired.</param>
        /// <param name="e">Arguments of the event include the Color selected</param>        
        public delegate void colorSelectedDelegate(object sender, oSoftColorPickerEventArgs e);

        /// <summary>
        /// Event raised when a color is selected in the ColorPicker
        /// </summary>
        [Description("Event raised when a color is selected in the ColorPicker")]
        public event colorSelectedDelegate ColorSelected;

        private void tbHex_Validating(object sender, CancelEventArgs e)
        {
            if (!System.Text.RegularExpressions.Regex.IsMatch(tbHex.Text, "^#[0-9a-fA-F]{6}$"))
            {
                e.Cancel = true;
            }

        }

        private void tbHex_Validated(object sender, EventArgs e)
        {

            if (tbHex.Text != oldHexValue)
            {
                string r, g, b;

                r = tbHex.Text.Substring(1, 2);
                g = tbHex.Text.Substring(3, 2);
                b = tbHex.Text.Substring(5, 2);

                Color = Color.FromArgb(
                    int.Parse(r, System.Globalization.NumberStyles.HexNumber),
                    int.Parse(g, System.Globalization.NumberStyles.HexNumber),
                    int.Parse(b, System.Globalization.NumberStyles.HexNumber));

                if (ColorSelected != null)
                {
                    object s = this;
                    oSoftColorPickerEventArgs ce = new oSoftColorPickerEventArgs();
                    ce.color = Color;
                    ColorSelected(s, ce);
                }     
            }
        }

        private void tbColor_Validating(object sender, CancelEventArgs e)
        {
            string s;

            s = ((TextBox)sender).Text;
            e.Cancel = !System.Text.RegularExpressions.Regex.IsMatch(s, "(^[0-9]{1,2}$)|(^1[0-9][0-9]$)|(^2([0-4][0-9])|(5[0-5])$)");
        }

        private void tbHue_Validating(object sender, CancelEventArgs e)
        {
            string s;

            s = ((TextBox)sender).Text;
            e.Cancel = !System.Text.RegularExpressions.Regex.IsMatch(s, "(^[0-9]{1,2}$)|(^[1-2][0-9][0-9]$)|(^3([0-5][0-9])|(60)$)");
        }

        private void tbColor_Validated(object sender, EventArgs e)
        {
            string s;
            int b;
            Boolean changed = false;

            s = ((TextBox)sender).Text;
            b = int.Parse(s);

            switch (((TextBox)sender).Name.ToLower())
            {
                case "tbred":
                    if (changed = c.R != b)
                        c.R = b;
                    break;
                case "tbgreen":
                    if (changed = c.G != b)
                        c.G = b;
                    break;
                case "tbblue":
                    if (changed = c.B != b)
                        c.B = b;
                    break;
                case "tbhue":
                    if (changed = c.H != b)
                        c.H = b;
                    break;
                case "tbsaturation":
                    if (changed = c.S != b)
                        c.S = b;
                    break;
                case "tbluminosity":
                    if (changed = c.L != b)
                        c.L = b;
                    break;

            }

            if (changed)
            {
                showValues();
                paintColorImage();

                if (ColorSelected != null)
                {
                    object snd = this;
                    oSoftColorPickerEventArgs ce = new oSoftColorPickerEventArgs();
                    ce.color = Color;
                    ColorSelected(snd, ce);
                }
            }
        }



    }
}
